package com.lry.jvm.instructions.refrences;

import com.lry.jvm.instructions.base.Index16Instruction;
import com.lry.jvm.rtda.Frame;
import com.lry.jvm.rtda.JObject;
import com.lry.jvm.rtda.LocalVars;
import com.lry.jvm.rtda.OperandStack;
import com.lry.jvm.rtda.heap.FieldRef;
import com.lry.jvm.rtda.heap.JClass;
import com.lry.jvm.rtda.heap.JField;
import com.lry.jvm.rtda.heap.RuntimeConstantPool;
import com.lry.jvm.util.Util;

public class getfield extends Index16Instruction {
    @Override
    public byte getOpCode() {
        return (byte) 0xb4;
    }

    @Override
    public void execute(Frame frame) {
        RuntimeConstantPool rcp = frame.getMethod().getJClass().getConstantPool();
        FieldRef fieldRef = (FieldRef) rcp.getConstant(index);
        JField field = fieldRef.resolvedField();
        JClass fieldClass = field.getJClass();

        if(field.isStatic()){
            Util.panic("java.lang.IncompatibleClassChangeError");
        }

        OperandStack stack = frame.getOperandStack();
        JObject ref = stack.popRef();
        if (ref == null) {
            Util.panic("java.lang.NullPointerException");
        }
        String descriptor = field.getDescriptor();
        int slotId = field.getSlotId();
        LocalVars slots = ref.getInstanceVars();

        switch (descriptor.charAt(0)){
            case 'Z':
            case 'B':
            case 'C':
            case 'S':
            case 'I':
                stack.pushInt(slots.getInt(slotId));
                break;
            case 'F':
                stack.pushFloat(slots.getFloat(slotId));
                break;
            case 'J':
                stack.pushLong(slots.getLong(slotId));
                break;
            case 'D':
                stack.pushDouble(slots.getDouble(slotId));
                break;
            case '[':
            case 'L':
                stack.pushRef(slots.getRef(slotId));
                break;
        }

    }
}
